package GameMaze;

import java.util.Arrays;
import java.util.Observable;
//import java.util.Random;

import org.eclipse.swt.SWT;

import controller.Presenter;
import controller.XMLHandler;
import model.Model;
import model.State;

public class GameMazeModel extends Observable implements Model {
	private int[][] modelBoard;
	private int currentScore;
	private State currentState, tmpState;
	private int stepId = 0;

	// Random generator = new Random();
	// private int[] initOptions = new int[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 4 };

	public GameMazeModel() {
		modelBoard = new int[5][5];
		modelClearBoard();
		currentScore = 0;
		// int[][] playerGoalPosition = new int[2][2];

		currentState = new State(-1, currentScore, cloneBoard(modelBoard), null);
	}

	private int[][] GetPlayerGoalPosition() {
		int[][] pgPos = new int[5][5];
		for (int i = 0; i < modelBoard.length; i++) {
			for (int j = 0; j < modelBoard[i].length; j++) {
				if (modelBoard[i][j] == 1) {
					// player
					pgPos[0][0] = i;
					pgPos[0][1] = j;

				} else if (modelBoard[i][j] == 2) {
					// goal
					pgPos[1][0] = i;
					pgPos[1][1] = j;
				}
			}
		}
		return pgPos;
	}

	@Override
	public State moveUp(State currentState) {
		DoIfValid(0, -1);
		return null;
	}

	@Override
	public State moveDown(State currentState) {
		DoIfValid(0, 1);
		return null;
	}

	@Override
	public State moveLeft(State currentState) {
		DoIfValid(-1, 0);
		return null;
	}

	@Override
	public State moveRight(State currentState) {
		DoIfValid(1, 0);
		return null;
	}

	private void moveUpLeft() {
		DoIfValid(-1, -1);
	}

	private void moveUpRight() {
		DoIfValid(1, -1);
	}

	private void moveDownLeft() {
		DoIfValid(-1, 1);
	}

	private void moveDownRight() {
		DoIfValid(1, 1);
	}

	private void DoIfValid(int x, int y) {
		int[] player = GetPlayerGoalPosition()[0];
		int[] goal = GetPlayerGoalPosition()[1];

		// Check id valid move
		if (0 <= player[0] + x && player[0] + x < modelBoard.length
				&& 0 <= player[1] + y && player[1] + y < modelBoard.length
				&& modelBoard[player[0] + x][player[1] + y] != -1) {
			modelBoard[player[0]][player[1]] = 0;
			modelBoard[player[0] + x][player[1] + y] = 1;
			if (x == 0 || y == 0) {
				currentScore += 10;
			} else {
				currentScore += 15;
			}
			tmpState = new State(stepId++, currentScore,
					cloneBoard(modelBoard), currentState);

			if (Arrays.equals(GetPlayerGoalPosition()[0], goal)) {
				modelBoard[goal[0]][goal[1]] = 3;
			}
		}
	}

	private void checkGameOver() {
			for (int i = 0; i < modelBoard.length; i++) {
				for (int j = 0; j < modelBoard.length; j++) {
					if (modelBoard[i][j] == 3) {
						modelBoard[0][0] = 10;
						
					}
				}
			}
					
				

	}

	@Override
	public int[][] getData() {
		return this.modelBoard;
	}

	private void notifyToObservers() {
		setChanged();
		notifyObservers();
	}

	@Override
	public void addObserver(Presenter p) {
		super.addObserver(p);
	}

	@Override
	public void updateMe(int userCommand, String filePath) {		
		if(userCommand == -5){
//			userCommand = need to add the func that decide witch move will be activate
		}
		switch (userCommand) {
		case -1: // NewGame
			modelClearBoard();
			// initOptionsGenerator();
			// initOptionsGenerator();
			break;
		case -2: // Save
			SaveState(tmpState, filePath);
			break;
		case -3: // Load
			State loaded = LoadState(filePath);
			currentState = loaded;
			modelBoard = cloneBoard(loaded.boardState);
			currentScore = loaded.score;
			stepId = loaded.stateId;
			break;
		case -4: // Undo
			UndoMove();
			break;
		case SWT.ARROW_UP:
			moveUp(null);
			break;
		case SWT.ARROW_DOWN:
			moveDown(null);
			break;
		case SWT.ARROW_LEFT:
			moveLeft(null);
			break;
		case SWT.ARROW_RIGHT:
			moveRight(null);
			break;
		case SWT.ARROW_UP + SWT.ARROW_LEFT:
			moveUpLeft();
			break;
		// case SWT.ARROW_UP + SWT.ARROW_RIGHT: //TODO: BUG!
		// moveUpRight();
		// break;
		case SWT.ARROW_DOWN + SWT.ARROW_LEFT:
			moveDownLeft();
			break;
		case SWT.ARROW_DOWN + SWT.ARROW_RIGHT:
			moveDownRight();
			break;
		default:
			int posX = userCommand / 1000;
			int posY = userCommand / 100 % 10;
			if (GetPlayerGoalPosition()[0][0] == posX
					&& GetPlayerGoalPosition()[0][1] > posY) {
				moveUp(null);
			} else if (GetPlayerGoalPosition()[0][0] == posX
					&& GetPlayerGoalPosition()[0][1] < posY) {
				moveDown(null);
			} else if (GetPlayerGoalPosition()[0][0] > posX
					&& GetPlayerGoalPosition()[0][1] == posY) {
				moveLeft(null);
			} else if (GetPlayerGoalPosition()[0][0] < posX
					&& GetPlayerGoalPosition()[0][1] == posY) {
				moveRight(null);
			}
			break;
		}
		if (stepId != -1 && userCommand != -4
				&& !currentState.isEquals(tmpState)) {
			// initOptionsGenerator();
			currentState = tmpState;
		}
		
		notifyToObservers();
	}

	private State LoadState(String filePath) {
		State st = null;
		try {
			st = XMLHandler.read(filePath);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return st;
	}

	private void SaveState(State stateToSave, String filePath) {
		try {
			XMLHandler.write(stateToSave, filePath);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void UndoMove() {
		if (currentState.pState != null) {
			modelBoard = cloneBoard(currentState.pState.boardState);
			currentScore = currentState.pState.score;
			stepId -= 1;
			currentState = currentState.pState;
		}
	}

	private void modelClearBoard() {
		for (int i = 0; i < modelBoard.length; i++) {
			for (int j = 0; j < modelBoard[i].length; j++) {
				modelBoard[i][j] = 0;
			}
		}

		modelBoard[0][0] = 2;
		modelBoard[4][4] = 1;
		modelBoard[1][0] = -1;
		modelBoard[1][1] = -1;
		modelBoard[1][2] = -1;
		modelBoard[1][3] = -1;
		modelBoard[3][1] = -1;
		modelBoard[3][2] = -1;
		modelBoard[3][3] = -1;
		modelBoard[3][4] = -1;
		modelBoard[1][1] = -1;

		currentScore = 0;
	}

	@Override
	public int getScore() {
		return this.currentScore;
	}

	private int[][] cloneBoard(int[][] modelBoard) {
		int[][] newBoard = new int[modelBoard.length][modelBoard[0].length];
		for (int i = 0; i < modelBoard.length; i++) {
			for (int j = 0; j < modelBoard[i].length; j++) {
				newBoard[i][j] = modelBoard[i][j];
			}
		}
		return newBoard;
	}
	

}
